home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Science⁄Math / VideoToolbox / VideoToolboxSources / FlushCacheRange.c < prev    next >
Text File  |  1993-03-14  |  8KB  |  184 lines

  1. /*
  2. FlushCacheRange.c
  3. A machine and system independent cache flush routine.
  4.  
  5. Beginning with the Macintosh II, developers were faced with situations where
  6. instruction and/or data caches needed to be flushed for code to execute
  7. correctly.  Unfortunately, despite recent improvements (i.e. _HWPriv, see Tech
  8. Note #261), cache flushing remains highly CPU- and system-specific and developers
  9. have had difficulty doing it in a way that ensures both forward and backward
  10. compatibility.   FlushCacheRange.c contains a single function call that will work across
  11. all platforms, yet still provides access to such advanced MC68040 features as
  12. selective cache range flushing.
  13.  
  14. Dave Radcliffe Apple DTS January, 1992
  15.  
  16. ****************************************************************************
  17. NOTE: This routine was distributed by Apple on their Developer Disk for May, 1992.
  18. I changed the name of the file from Cache.c to FlushCacheRange.c, to match the
  19. name of the routine, moved the prototype from Cache.h to VideoToolbox.h,
  20. and pasted the contents of the "About..." file above. Otherwise the file is unchanged.
  21. You might need licensing from Apple to use this in a commercial application.
  22. Denis Pelli, July, 1992
  23. ****************************************************************************
  24.  *
  25.  *    Cache control is a highly CPU specific function.  Although some system independence
  26.  *    is achieved via use of the _HWPriv trap, this solution may not be general for all
  27.  *    hardware/system software combinations.  FlushCacheRange should solve that for
  28.  *    developers by working on all systems.
  29.  *    
  30.  *    Written by:    Dave Radcliffe
  31.  *
  32.  *    Copyright:    © 1991 by Apple Computer, Inc., all rights reserved.
  33.  *
  34.  *    Change History:
  35.  *
  36.  *        1/20/92        DR        Added System603OrLater conditional code
  37.  *        1/10/92        DR        Added FlushCacheWithCPushA()
  38.  *        12/18/91    DR        New today
  39.  *
  40.  */
  41.  
  42. #include "VideoToolbox.h"    /* for prototype of FlushCacheRange */
  43.  
  44. #ifndef __TYPES__
  45. #include <Types.h>
  46. #endif
  47.  
  48. #ifndef __TRAPS__
  49. #include <Traps.h>
  50. #endif
  51.  
  52. #ifndef __OSUTILS__
  53. #include <OSUtils.h>
  54. #endif
  55.  
  56. #ifndef __GESTALTEQU__
  57. #include <GestaltEqu.h>
  58. #endif
  59.  
  60. #ifndef __ERRORS__
  61. #include <Errors.h>
  62. #endif
  63.  
  64. /*
  65.  * If you can guarantee you are running on System 6.0.3 or later, then some of the
  66.  * alternative cache flushing code implemented below is unnecessary as you are
  67.  * assured of having the _HWPriv trap.  So, if you are running on System 6.0.3 or
  68.  * later, uncommenting the following line can reduce this code by more than half.
  69.  */
  70. /* #define System603OrLater */
  71.  
  72. /* The next two declarations are defined in Tech Note #261 */
  73. #ifndef FlushCodeCacheRange
  74. /* MPW C 3.1 and earlier, and THINK C should declare the function as   */
  75. /* “pascal” and use the same inline constants as the Pascal interface: */
  76. pascal OSErr FlushCodeCacheRange (void *address, unsigned long count) =
  77.     {0x225F, 0x205F, 0x7009, 0xA198, 0x3E80};
  78.     
  79. /* The above declaration works for MPW C 3.2 as well, but 3.2 allows   */
  80. /* register specifications to make register-based inline calls very    */
  81. /* efficient.  So, under MPW C 3.2, you may choose to uncomment the    */
  82. /* following code, instead.                                            */
  83. /*
  84. #pragma parameter __D0 FlushCodeCacheRange(__A0,__A1)
  85. OSErr FlushCodeCacheRange (void *address, unsigned long count) =
  86.     {0x7009, 0xA198};
  87. */
  88. #endif
  89.  
  90. #ifndef FlushCodeCache
  91. #define _CacheFlush 0xA0BD
  92. void FlushCodeCache (void) = _CacheFlush;
  93. #endif
  94.  
  95. /* 
  96.  * FlushCacheViaCACR is an inline assembly routine that flushes both the 
  97.  * instruction and data caches by writing directly to the CACR.  Used only
  98.  * as a last resort by FlushCacheRange
  99.  */
  100. void FlushCacheViaCACR ( void ) =
  101.     { 0x4E7A, 0x0002,        /* MOVEC    CACR,D0 */
  102.       0x08C0, 0x0003,        /* BSET        #3,D0   */
  103.       0x4E7B, 0x0002 };        /* MOVEC    D0,CACR */
  104.  
  105. /*
  106.  * FlushCacheWithCPushA is another inline assembly routine that flushes caches
  107.  * on the MC68040 using the CPushA instruction.  Used only as a last resort
  108.  * by FlushCacheRange
  109.  */
  110. void FlushCacheWithCPushA ( void ) =
  111.     { 0x4E71,                /* NOP, to clear pending writes */
  112.       0xF4F8 };                /* CPUSHA    BC */
  113.       
  114. /*
  115.  * FlushCacheRange flushes both the data and instruction caches for the block of 
  116.  * memory starting at location address with size count.  Flushing the cache for 
  117.  * a range of memory is only supported on the 68040, so if this functionality is
  118.  * unavailable, the entire cache is flushed (if appropriate).
  119.  *
  120.  * If either address is NIL or count is zero, the entire cache is flushed anyway.
  121.  * Selective flushing of the cache is a time consuming process and you may wish to
  122.  * avoid it when there is no benefit to doing so.  For example, if you've recently
  123.  * manipulated a block larger than 4K (the size of the 68040 caches), selective
  124.  * flushing will probably end up flushing the entire cache anyway, so why bother?
  125.  *
  126.  * The preferred method for flushing the cache is to use the _HWPriv trap documented
  127.  * in Tech Note #261.  Some older systems may not have this trap implemented, so
  128.  * alternate methods must be used.  The first thing to try is the _CacheFlush trap.
  129.  * This was implemented beginning with the Mac II (and is also documented in Tech
  130.  * Note #261).
  131.  *
  132.  * MC68000 based systems have no cache, but if an accelerator board has been added.
  133.  * they may have a CPU which does have a cache.  Accelerator board vendors should
  134.  * implement _HWPriv or _CacheFlush for such systems, but if they haven't then
  135.  * our last resort is to control the caches directly (using privileged
  136.  * instructions (GAK!!)).
  137.  *
  138.  * FINALLY, the full implementation of FlushCacheRange is probably overkill and may be 
  139.  * less than optimal for some applications.  For example, testing for _HWPriv 
  140.  * should be unnecessary on systems later than 6.0.2, so I've added conditional code
  141.  * to allow you to bypass that if appropriate (see comment above on System603OrLater).
  142.  * The full implementation tries to cover a lot of obscure cases, but it also does 
  143.  * some things inefficiently.  For example, having determined the _HWPriv is 
  144.  * implemented, it would be more efficient to just keep that information around, 
  145.  * but I wanted to avoid the complications of global or static variables.  But 
  146.  * it is also true that if you find it necessary to call this code more than a
  147.  * few times between the time your application starts and the time it quits, 
  148.  * YOU ARE DOING SOMETHING WRONG!!   Go back and rethink your code.
  149.  */
  150. void FlushCacheRange (void *address, unsigned long count)
  151. {
  152. #ifndef System603OrLater
  153.     long    gestaltResponse;            /* For CPU type */
  154.     long    unimpTrapAddress;            /* Address of Unimplemented Trap */
  155.     
  156.     /* First check to see if _HWPriv is implemented */
  157.     if ((unimpTrapAddress = NGetTrapAddress(_Unimplemented, ToolTrap)) != 
  158.         NGetTrapAddress(_HWPriv, OSTrap)) {
  159. #endif
  160.         /* 
  161.          * Try to flush the specified range.  If it fails or if there is no range,
  162.          * then flush the entire cache 
  163.          */
  164.         if (!(address && count && (FlushCodeCacheRange (address, count) != hwParamErr))) {    
  165.             /* Flush entire cache */
  166.             FlushInstructionCache ();
  167.         }
  168. #ifndef System603OrLater
  169.     } else {                /* No _HWPriv trap */
  170.         /* Try for _CacheFlush trap */
  171.         if (unimpTrapAddress != NGetTrapAddress(_CacheFlush, OSTrap))
  172.             FlushCodeCache ();
  173.         else        /* Nothing else works, so do machine specific cache control */
  174.             /* Only bother with cache control on 68020 and above */
  175.             if (!Gestalt (gestaltProcessorType, &gestaltResponse) && 
  176.                 (gestaltResponse >= gestalt68020))
  177.                     if (gestaltResponse <= gestalt68030)
  178.                         FlushCacheViaCACR ();
  179.                     else
  180.                         FlushCacheWithCPushA ();
  181.     }
  182. #endif
  183.     return;
  184. }    /* FlushCacheRange */